package p.ithorns.support.license.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.ResourceUtils;
import p.ithorns.framework.common.codec.AESCodec;
import p.ithorns.framework.common.codec.MD5Codec;
import p.ithorns.framework.common.codec.RSACodec;
import p.ithorns.framework.common.utils.StringUtil;
import p.ithorns.framework.common.utils.*;
import p.ithorns.support.license.model.Authorize;
import p.ithorns.support.license.model.License;
import p.ithorns.support.license.model.LicenseBody;
import p.ithorns.support.license.model.LicenseException;

import javax.crypto.SecretKey;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * ClientGrantService
 * 客户端授权服务
 *
 * @author Ht.L
 * @date 2023-12-13 09:50
 * @since 1.0.0
 */
@Slf4j
@Service
public class GrantClientService {

    private final LicenseService licService;

    private final String clientId;

    private final static Map<String, Authorize> AUTHORIZE_MAP = new ConcurrentHashMap<>();

    public GrantClientService(LicenseService licService) throws Exception {
        this.licService = licService;
        this.clientId = genClientId();
    }

    /**
     * 生成客户端ID
     * 这个方法是幂等的
     *
     * @return String
     * @throws Exception -
     */
    public String genClientId() throws Exception {
        String md5 = MD5Codec.md5(DeviceUtil.getSn(), "KyLE");
        return Base64.getEncoder().encodeToString(md5.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * 从文件加载授权信息
     *
     * @throws Exception -
     */
    public void loadLocalAuth() throws Exception {
        // String filePath = FileUtil.getFilePath(clientId);
        URL url = ResourceUtils.getURL(clientId);
        Path path = Paths.get(url.toURI());

        // base64解码
        byte[] bytes = Base64.getDecoder().decode(Files.readAllBytes(path));
        String content = new String(bytes, StandardCharsets.UTF_8);

        // 分解授权码和公钥
        String[] split = StringUtil.split(content, "@");
        if (split.length < 2) {
            throw new RuntimeException("无效的授权文件");
        }
        String authCode = split[0];
        String publicKey = split[1];
        log.info("加载授权码和PubKey -> {}, {}", authCode, publicKey);

        // 存储授权信息
        storeAuth(publicKey, authCode);
    }

    /**
     * 解密证书文件
     *
     * @return License
     * @throws Exception -
     */
    public License decrypt(LicenseBody body) throws Exception {
        // 证书签名
        String sign = body.getSign();
        // 证书密文
        String cipher = body.getCipher();

        // 拿到公钥和授权码
        String publicKey = getPublicKey();
        String authCode = getAuthCode();

        // 先用公钥解密
        String rsaDecrypt = RSACodec.decryptPublic(cipher, publicKey);

        // 客户端进行校验
        boolean verify = RSACodec.verify(rsaDecrypt, publicKey, sign);
        log.info("【客户端】-> RSA公钥验证: {}", verify);
        if (!verify) {
            throw new LicenseException("证书校验失败.");
        }

        // 客户端通过同样算法生成AES-Key
        String feed = Grantor.genAuthCode(clientId, authCode);
        log.info("【客户端】-> 生成feed: {}", feed);
        SecretKey secretKey = AESCodec.generateKey(feed);
        String aesKey = AESCodec.encodeKey(secretKey);
        log.info("【客户端】-> 生成AES-Key: {}", aesKey);

        // AES解密
        String aesDecrypt = AESCodec.decrypt(rsaDecrypt, secretKey);
        log.info("【客户端】-> AES解密：{}", aesDecrypt);

        License lic = JsonUtil.fromJson(aesDecrypt, License.class);
        log.info("【客户端】-> RSA公钥解密 {}", lic);
        return lic;
    }

    private void storeAuth(String publicKey, String authCode) {
        Authorize auth = new Authorize(publicKey, authCode);
        AUTHORIZE_MAP.put("AUTH", auth);
    }

    private String getPublicKey() {
        Authorize auth = AUTHORIZE_MAP.get("AUTH");
        return auth.getPublicKey();
    }

    public String getAuthCode() {
        Authorize auth = AUTHORIZE_MAP.get("AUTH");
        return auth.getAuthCode();
    }

    //String cipher = "dhghBJwPahIjVN1/FdIkl7DR8tdNE50hiY2rugazauRJ4tmV1j+LbfZCq1Fdc6BUe31T/za6lka911kOWGdcLyr4PM5cgfFOk/IguBYSGwdjAPecMV8ckyAjoTxyRQsj5mVA6itgwZFdjG8UGge2nXsbRatOJCAuTBSr03hmK3Z7LFyWTzOvFgADrsdB5zUSyRJkcpBwkBP93W5xeo//zFAQrpJZY317qiz3/dYzRnEA8Ch3alN0B3pya3bRTW4C9x8ymIgozdlu5dSzi7jqYrO3s5C4rMDIIzyie4+RHkAjyqMrlAmFCjR/iyDaKdF6OZneEYn1k9lTTik071fE5A==";
    //String sign = "Mic4EhAAzqdKIOBTskqH8+SUbTi3PcY/xI6gywrN2mp2+f0Po7zLQQTw1ecer0rJAEK44DMjxRJUNkGAoCiuj3+mIMNnb8EI4T2E9Ypnr5w6SGnyQrvdB/1vW1esfCF9TwVfiLpbEkQgd9pfBozYL+DW7GMU3Hs74HdlTFTq0qw=";

}